﻿using System;
using System.Collections.Generic;
using System.Text;
using OpenPOP.POP3;
using OpenPOP.MIMEParser;
using System.Collections;
using System.IO;
using FaxServerNET.Security;
using System.Net.Mail;
using System.Net.Mime;
using System.Text.RegularExpressions;
using log4net;
using System.Net;

namespace FaxServerNET.Email
{
    public class EmailClient : IFaxRelayer
    {
        private static readonly ILog _log = LogManager.GetLogger(typeof(EmailClient));
        private POPClient _pop_client = new POPClient();
        public string PopServer { get; set; }
        public int PopPort { get; set; }

        public string ReceiverEmailAddress { get; set; } //The email address where you want to send the received faxes
        public string FaxServerEmailAddress { get; set; } //The email address that will show up in the "From" field of the received fax email
        public string ReceivedFaxEmailSubject { get; set; }
        public string ReceivedFaxEmailContent { get; set; }
        public string SmtpServer { get; set; }
        public int SmtpPort { get; set; }

        public string POPUsername { get; set; }
        public string POPPassword { get; set; }
        public bool POPUseSSL { get; set; }

        public string SMTPUsername { get; set; }
        public string SMTPPassword { get; set; }
        public bool SMTPUseSSL { get; set; }
        public bool SMTPUseAuthentication { get; set; }

        public bool DeleteMessagesOnServer { get; set; }
        public ISecurityProvider SecurityProvider { get; set; }

        public EmailClient()
        {
            _log.InfoFormat("Using EmailClient FaxRelayer");
        }

        public List<FileToFax> GetFilesToFax()
        {
            List<FileToFax> files_to_fax = new List<FileToFax>();
            _log.InfoFormat("Checking POP3 messages");
            lock (_pop_client)
            {
                try
                {
                    _log.DebugFormat("Connecting to server {0}:{1}[ssl:{2}]",PopServer,PopPort,POPUseSSL);
                    _pop_client.Connect(PopServer, PopPort, POPUseSSL);
                    _log.DebugFormat("Using username:{0} password:xxxxxxx", POPUsername);
                    _pop_client.Authenticate(POPUsername, POPPassword);

                    int Count = _pop_client.GetMessageCount();
                    _log.InfoFormat("POP3 messages found {0}",Count);

                    string to_fax_number, filename_of_fax;

                    for (int i = 1; i <= Count; i++)
                    {
                        Message m = _pop_client.GetMessage(i, false);
                        if (m != null)
                        {
                            ArrayList attachments = m.Attachments;
                            foreach (OpenPOP.MIMEParser.Attachment attachment in attachments)
                            {
                                string filename = m.GetAttachmentFileName(attachment);
                                if (!(filename.ToLower().Substring(0, 8) == "body.htm"))
                                {
                                    if (SecurityProvider.CanSendFax(m))
                                    {
                                        //write file
                                        byte[] file_contents = attachment.DecodedAsBytes();
                                        filename_of_fax = writeByteArrayToFile(file_contents, filename, m.FromEmail);
                                        if (filename_of_fax.Length > 0)
                                        {
                                            to_fax_number = CleanFaxNumber(m.Subject);
                                            var fax = new FileToFax(filename_of_fax, to_fax_number)
                                                {
                                                    SenderAddress = m.ReplyToEmail ?? m.FromEmail
                                                };
                                            _log.InfoFormat("Reading a fax from to {2}-[{1}], from {0}",fax.SenderAddress,filename_of_fax,fax.FaxNumber);
                                            files_to_fax.Add(fax);
                                        }
                                    }
                                }

                            }
                            if (DeleteMessagesOnServer)
                                _pop_client.DeleteMessage(i);
                        }
                    }
                    _pop_client.Disconnect();
                    List<FaxStatus> statuses_sent = new List<FaxStatus>();
                    //Try sending all the queued statuses
                    foreach (var status in _statuses_to_send)
                    {

                        if (SendMessageWithAttachment(status.File.SenderAddress, FaxServerEmailAddress,
                            "Fax status", status.StatusMsg, null))
                        {
                            statuses_sent.Add(status);
                        }
                    }
                    //Clean up the statuses queue
                    foreach (var status in statuses_sent)
                    {
                        _statuses_to_send.Remove(status);
                    }
                }
                catch (Exception e)
                {
                    _log.Error(e);
                }
            }
            return files_to_fax;

        }

        public static string CleanFaxNumber(string number)
        {
            string to_fax_number;
            to_fax_number = Regex.Replace(number, "[^0-9,]", "");
            return to_fax_number;
        }

        List<FaxStatus> _statuses_to_send = new List<FaxStatus>();
        public void SendFaxStatus(FileToFax file_faxed, string status_msg)
        {
            _log.Info(status_msg);
            if (!SendMessageWithAttachment(file_faxed.SenderAddress, FaxServerEmailAddress,
                "Fax status", status_msg, null))
            {
                _statuses_to_send.Add(new FaxStatus() { File = file_faxed, StatusMsg = status_msg });
            }
        }

        public void SendFaxReceived(string fax_file_path)
        {
            SendMessageWithAttachment(ReceiverEmailAddress, FaxServerEmailAddress,
                ReceivedFaxEmailSubject, ReceivedFaxEmailContent, fax_file_path);
        }

        //parts taken from http://kseesharp.blogspot.com/2007/12/write-byte-array-to-file.html
        string writeByteArrayToFile(byte[] buff, string fileName, string from_email_address)
        {
            string full_file_path = "";
            try
            {
                foreach (char invalid_char in Path.GetInvalidFileNameChars())
                {
                    from_email_address = from_email_address.Replace(invalid_char, 'x');
                    fileName = fileName.Replace(invalid_char, 'x');
                }
                if (!(Directory.Exists(from_email_address)))
                {
                    Directory.CreateDirectory(from_email_address);
                }
                FileStream fs = new FileStream(Path.Combine(from_email_address, fileName), FileMode.Create, FileAccess.ReadWrite);
                BinaryWriter bw = new BinaryWriter(fs);
                bw.Write(buff);
                bw.Close(); //Thanks Karlo for pointing out!
                full_file_path = Path.Combine(from_email_address, fileName);
            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
            return full_file_path;
        }

        //Send Emails logic (modified from http://www.c-sharpcorner.com/UploadFile/scottlysle/EmailAttachmentsCS08052008234321PM/EmailAttachmentsCS.aspx)

        /// <summary>
        /// Transmit an email message with
        /// attachments
        /// </summary>
        /// <param name="sendTo">Recipient Email Address</param>
        /// <param name="sendFrom">Sender Email Address</param>
        /// <param name="sendSubject">Subject Line Describing Message</param>
        /// <param name="sendMessage">The Email Message Body</param>
        /// <param name="attachments">A string array pointing to the location   of each attachment</param>
        /// <returns>Status Message as String</returns>
        public bool SendMessageWithAttachment(string sendTo, string
        sendFrom, string sendSubject, string sendMessage, string
        attachment)
        {
            bool msg_sent = false;
            try
            {


                // Create the basic message

                MailMessage message = new MailMessage(
                   sendFrom,
                   sendTo,
                   sendSubject,
                   sendMessage);

                // The attachment should point to a file location   
                // where the attachment resides - add the attachments to the
                // message
                if (attachment != null)
                {
                    System.Net.Mail.Attachment attached = new System.Net.Mail.Attachment(attachment,
                    MediaTypeNames.Application.Octet);
                    message.Attachments.Add(attached);
                }

                // create smtp client at mail server location
                SmtpClient client = new
                SmtpClient(SmtpServer, SmtpPort);

                if (SMTPUseAuthentication)
                {
                    client.Credentials = new NetworkCredential(SMTPUsername, SMTPPassword);
                    client.EnableSsl = SMTPUseSSL;
                    client.Timeout = 20000;
                }
                // Add credentials
                //client.UseDefaultCredentials = true;

                // send message
                client.Send(message);

                msg_sent = true;


            }
            catch (Exception ex)
            {
                msg_sent = false;
                _log.Error(ex);
            }
            return msg_sent;
        }

    }
}
